// 函数柯理化  多个参数的传入  把它转化成 n个函数
// 一般柯理化ha参数要求都是  一个一个的传； 如果有的传的是两个或者n个，也可以叫柯理化，准确叫法应该是“偏函数”
// 做类型判断的时候就需要使用柯理化函数了

// 判断一个变量的类型：（代码的实现，类型是基本条件）
/**
 * typeof: 只能判断简单数据类型，复杂类型判断不了，返回的都是object，所以一般用于判断基础类型
 *
 *
 *instanceof: 用于判断谁是谁的实例；（它的原理是什么？其实就是while循环，不停的找链，可以自己研究）
 *
 *
 * Object.prototype.toString.call() : 判断具体类型，返回的是一个字符串
 *
 *
 * constructor:深拷贝
 */

//  我们的柯理化登场，让函数变得更具体一些，有柯理化，当然也有 反柯理化：就让函数范围变得更大一些
// function isType(val, typing) {
//   return Object.prototype.toString.call(val) == `[object ${typing}]`;
// }
// console.log(isType('abc', 'String'));

function isString(typing) {
  return function (val) {
    // 这样的写法就是将变量存放到了这个函数内
    return Object.prototype.toString.call(val) == `[object ${typing}]`;
  };
}
// let myIsString = isString('String');

// console.log(myIsString('abc'));
// console.log(myIsString(123));

// 实现通用的柯理化函数，其实就是高阶函数
// 柯理化一般是知道参数是已知个数的*

function curring(fn) {
  // 存储每次调用的时候传入的变量fn

  // console.log('看看每次传入的fn是什么：', fn.length);

  const inner = (args = []) => {
    // 存储每次调用时传入的参数args

    // 判断：当参数个数大于调用次数以后，就进行最后汇总执行，如果还小于调用次数，就递归
    return args.length >= fn.length
      ? fn(...args)
      : (...newArgs) => inner([...args, ...newArgs]); //
  };
  return inner();
}

// function sum(a, b, c, d) {
//   // 我要记录每次调用时传入的参数个数，并且和函数的参数个数进行比较
//   return a + b + c + d;
// }
// let sum1 = curring(sum);
// let sum2 = sum1(1);
// let sum3 = sum2(2, 3);
// let result = sum3(4);
// console.log(result);

function isType(typing, val) {
  return Object.prototype.toString.call(val) == `[object ${typing}]`;
}

let util = {};
['String', 'Number', 'Boolean', 'Null', 'Undefined'].forEach(type => {
  util['is' + type] = curring(isType)(type);
});
// let myString = curring(isType)('String');
// console.log('测试结果：', myString('abc'));
// let myNumber = curring(isType)('Number');
// console.log('测试number：', myNumber(123));

console.log('结果：', util.isString('abc'));

// 柯理化的应用：
// 需求：多个接口，请求数据，等待数据返回后，再去渲染页面
